using System;
using System.Collections.Generic;
using System.Linq;
using System.Configuration;
using CommonLogging;
using System.Web.Security;
using TestWeb.Models;
using TestWeb.Helpers;
using TestWeb.ViewModels;

namespace TestWeb.Repositories
{	
	/// <summary>
	/// The class is responsible for accessing table NguoiDung in database
	/// </summary>
	public class NguoiDungRepository
	{
		#region Fields
		
		/// <summary>
		/// The role name is SUPERADMIN
		/// </summary>
		public readonly string ConstSuperAdmin = "SUPERADMIN";

		/// <summary>
		/// The role name is ADMIN
		/// </summary>
		public readonly string ConstAdmin = "ADMIN";

		/// <summary>
		/// Get the number of elements in table NguoiDung
		/// </summary>
		public int? TotalElems { get; set; }

		/// <summary>
		/// Calculate total pages from total items and page size
		/// </summary>
		public int TotalPages
		{
			get
			{
				if (this.TotalElems.HasValue && this.TotalElems.Value > 0)
					return (this.TotalElems.Value / WebConfiguration.Instance.NumNguoiDungPerPage) + ((this.TotalElems.Value % WebConfiguration.Instance.NumNguoiDungPerPage == 0) ? 0 : 1);
				return 0;
			}
		}

		/// <summary>
		/// The logger instance
		/// </summary>
		public readonly ILogger Logger = LoggerManager.GetLogger(typeof(NguoiDungRepository).Name);

		#endregion
		
		#region Methods
		
		/// <summary>
		/// Select range of elements in the table NguoiDung
		/// </summary>
		/// <param name="Role">The role of current active user</param>
		/// <param name="Page">The page which user want to go to</param>
		/// <returns>The collection of elements from Model</returns>
		public List<NguoiDungModel> Select(string Role, int Page)
		{
			var lstItem = new List<NguoiDungModel>();
			try
			{
				var userCollection = Membership.GetAllUsers();
				
				foreach (MembershipUser user in userCollection)
				{
					var allowAdd = false;
					var roleForUser = Roles.GetRolesForUser(user.UserName)[0];
					
					if (string.Compare(Role, this.ConstSuperAdmin, StringComparison.OrdinalIgnoreCase) == 0)
					{
						if (string.Compare(roleForUser, this.ConstSuperAdmin, StringComparison.OrdinalIgnoreCase) != 0)
							allowAdd = true;
					}
					else if (string.Compare(roleForUser, this.ConstAdmin, StringComparison.OrdinalIgnoreCase) == 0)
					{
						if (string.Compare(roleForUser, this.ConstSuperAdmin, StringComparison.OrdinalIgnoreCase) != 0 && 
							string.Compare(roleForUser, this.ConstAdmin, StringComparison.OrdinalIgnoreCase) != 0)
							allowAdd = true;
					}
					
					if (allowAdd)
					{
						NguoiDungModel userModel = new NguoiDungModel
						{
							UserName = user.UserName,
							Email = user.Email,
							Role = Roles.GetRolesForUser(user.UserName)[0],
                            IsEnable = user.IsApproved,
							NguoiDung = DataContext.Instance.NguoiDung.FirstOrDefault(n => n.ID == (Guid)user.ProviderUserKey)
						};
						lstItem.Add(userModel);
					}
				}
				
				this.TotalElems = lstItem.Count;
				lstItem = lstItem.Skip((Page - 1) * WebConfiguration.Instance.NumNguoiDungPerPage).Take(WebConfiguration.Instance.NumNguoiDungPerPage).ToList();
			}
			catch(Exception ex)
			{
				if(ex.InnerException == null)
					Logger.ErrorFormat("Select: {0}", ex.Message);
				else
					Logger.ErrorFormat("Select: {0}", ex.InnerException.Message);
			}
			
			return lstItem;
		}

        /// <summary>
        /// Select range of elements belong to Page from 1 to CurrentPageLoaded in the table NguoiDung
        /// </summary>
        /// <param name="Role">The role of current active user</param>
        /// <param name="CurrentPageLoaded">The page which user want to go to</param>
        /// <returns>The collection of elements from Model</returns>
        public List<NguoiDungModel> SelectToPage(string Role, int CurrentPageLoaded)
        {
            var lstItem = new List<NguoiDungModel>();
            try
            {
                var userCollection = Membership.GetAllUsers();

                foreach (MembershipUser user in userCollection)
                {
                    var allowAdd = false;
                    var roleForUser = Roles.GetRolesForUser(user.UserName)[0];

                    if (string.Compare(Role, this.ConstSuperAdmin, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        if (string.Compare(roleForUser, this.ConstSuperAdmin, StringComparison.OrdinalIgnoreCase) != 0)
                            allowAdd = true;
                    }
                    else if (string.Compare(roleForUser, this.ConstAdmin, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        if (string.Compare(roleForUser, this.ConstSuperAdmin, StringComparison.OrdinalIgnoreCase) != 0 &&
                            string.Compare(roleForUser, this.ConstAdmin, StringComparison.OrdinalIgnoreCase) != 0)
                            allowAdd = true;
                    }

                    if (allowAdd)
                    {
                        NguoiDungModel userModel = new NguoiDungModel
                        {
                            UserName = user.UserName,
                            Email = user.Email,
                            Role = Roles.GetRolesForUser(user.UserName)[0],
                            IsEnable = user.IsApproved,
                            NguoiDung = DataContext.Instance.NguoiDung.FirstOrDefault(n => n.ID == (Guid)user.ProviderUserKey)
                        };
                        lstItem.Add(userModel);
                    }
                }

                this.TotalElems = lstItem.Count;
                lstItem = lstItem.Take(CurrentPageLoaded * WebConfiguration.Instance.NumNguoiDungPerPage).ToList();
            }
            catch (Exception ex)
            {
                if (ex.InnerException == null)
                    Logger.ErrorFormat("Select: {0}", ex.Message);
                else
                    Logger.ErrorFormat("Select: {0}", ex.InnerException.Message);
            }

            return lstItem;
        }

		/// <summary>
		/// Select specified element of table NguoiDung based on ID
		/// </summary>
		/// <param name="ID">The key to indentify an user</param>
		/// <returns>The specified element from Model</returns>
		public NguoiDungModel SelectByID(Guid ID)
		{
			NguoiDungModel userModel = null;
			try
			{
				var user = Membership.GetUser(ID);
				if (user != null)
				{
					userModel = new NguoiDungModel
					{
						UserName = user.UserName,
						Email = user.Email,
						Role = Roles.GetRolesForUser(user.UserName)[0],
						NguoiDung = DataContext.Instance.NguoiDung.FirstOrDefault(n => n.ID == (Guid)user.ProviderUserKey)
					};
				}
			}
			catch(Exception ex)
			{
				if(ex.InnerException == null)
					Logger.ErrorFormat("SelectByID: {0}", ex.Message);
				else
					Logger.ErrorFormat("SelectByID: {0}", ex.InnerException.Message);
			}
			return userModel;
		}

		/// <summary>
		/// Select specified element of table NguoiDung based on UserName
		/// </summary>
		/// <param name="UserName">The UserName of current active user</param>
		/// <returns>The specified element from Model</returns>
		public NguoiDungModel SelectByUserName(string UserName)
		{
			NguoiDungModel userModel = null;
			try
			{
				var user = Membership.GetUser(UserName);
				if (user != null)
				{
					userModel = new NguoiDungModel
					{
						UserName = user.UserName,
						Email = user.Email,
						Role = Roles.GetRolesForUser(user.UserName)[0],
						NguoiDung = DataContext.Instance.NguoiDung.FirstOrDefault(n => n.ID == (Guid)user.ProviderUserKey)
					};
				}
			}
			catch(Exception ex)
			{
				if(ex.InnerException == null)
					Logger.ErrorFormat("SelectByUserName: {0}", ex.Message);
				else
					Logger.ErrorFormat("SelectByUserName: {0}", ex.InnerException.Message);
			}
			return userModel;
		}

		/// <summary>
		/// Checking whether user is valid or not
		/// </summary>
		/// <param name="UserName">The username of user</param>
		/// <param name="Password">The password of user</param>
		/// <returns>Empty: user is valid and against</returns>
		public string ValidateUser(string UserName, string Password)
		{
			string errtxt = string.Empty;
			try
			{
				var result = Membership.ValidateUser(UserName, Password);
				if (!result)
					errtxt = "Login failed or invalid user!";
			}
			catch(Exception ex)
			{
				if(ex.InnerException == null)
					Logger.ErrorFormat("ValidateUser: {0}", ex.Message);
				else
					Logger.ErrorFormat("ValidateUser: {0}", ex.InnerException.Message);
			}
			return errtxt;
		}

		/// <summary>
		/// Insert a new element to table NguoiDung
		/// </summary>
		/// <param name="newElem">The element will be inserted</param>
		/// <param name="errTxt">The error text</param>
		/// <returns>True: successful - False: failed</returns>
		public bool Insert(NguoiDungModel newElem, ref string errTxt)
		{
			errTxt = string.Empty;
			try
			{
				MembershipCreateStatus createStatus;
				MembershipUser newUser = Membership.CreateUser(newElem.UserName, newElem.Password, newElem.Email, 
											"What is your favouritr color?", "Black Or White", true, out createStatus);
											
				switch (createStatus)
				{
					case MembershipCreateStatus.Success:
						Roles.AddUserToRole(newElem.UserName, newElem.Role);
                        // Add extra information
                        newElem.NguoiDung.ID = (Guid)newUser.ProviderUserKey;
                        DataContext.Instance.NguoiDung.AddObject(newElem.NguoiDung);
                        DataContext.Instance.SaveChanges();
						break;
						
					default:
                        errTxt = AccountValidation.ErrorCodeToString(createStatus);
						break;
				}
				
				if (!errTxt.Equals(string.Empty))
					return false;
				
				return true;
			}
			catch(Exception ex)
			{
				if (ex.InnerException == null)
					errTxt = string.Format("Insert: {0}", ex.Message);
				else
					errTxt = string.Format("Insert: {0}", ex.InnerException.Message);
				Logger.Error(errTxt);
			}
			return false;
		}

		/// <summary>
		/// Delete an element in table NguoiDung
		/// </summary>
		/// <param name="ID">The key for identifying an element</param>
		/// <param name="errTxt">The error text</param>
		/// <returns>True: successful - False: failed</returns>
		public bool Delete(Guid ID, ref string errTxt)
		{
			errTxt = string.Empty;
            NguoiDung delitem = null;
			try
			{
				delitem = DataContext.Instance.NguoiDung.FirstOrDefault(n => n.ID == ID );
				if (delitem != null)
				{
					DataContext.Instance.NguoiDung.DeleteObject(delitem);
					DataContext.Instance.SaveChanges();
					Membership.DeleteUser(Membership.GetUser(ID).UserName, true);
					return true;
				}
				else
					errTxt = string.Format("There is no any items with ID = {0} in table NguoiDung", ID.ToString());
			}
			catch(Exception ex)
			{
				if (ex.InnerException == null)
					errTxt = string.Format("Delete: {0}", ex.Message);
				else
					errTxt = string.Format("Delete: {0}", ex.InnerException.Message);

                DataContext.Instance.NguoiDung.Detach(delitem);
				Logger.Error(errTxt);
			}
			return false;
		}

		/// <summary>
		/// Update an specified element in table NguoiDung
		/// </summary>
        /// <param name="updateElem">The element will be inserted</param>
		/// <param name="errTxt">The error text</param>
		/// <returns>True: successful - False: failed</returns>
        public bool Update(NguoiDungModel updateElem, ref string errTxt)
		{
			errTxt = string.Empty;
			try
			{
                // For the base information, just update 2 attributes
                var user = Membership.GetUser(updateElem.UserName);
                if (user.IsApproved != updateElem.IsEnable || user.Email != updateElem.Email)
                {
                    user.IsApproved = updateElem.IsEnable;
                    user.Email = updateElem.Email;
                    Membership.UpdateUser(user);
                }

                // Update extra information
				DataContext.Instance.SaveChanges();
				return true;
			}
			catch(Exception ex)
			{
				if (ex.InnerException == null)
					errTxt = string.Format("Update: {0}", ex.Message);
				else
					errTxt = string.Format("Update: {0}", ex.InnerException.Message);
				Logger.Error(errTxt);
			}
			return false;
		}

		#endregion
		
	}
}

